<template>
  <el-card :body-style="{ padding: 0 }" class="department-tree-card">
    <template #header>
      <div class="card-header">
        <span class="title">组织架构</span>
        <div class="header-right">
          <el-button v-if="currentNode?.isExternal" size="small" type="primary" @click="handleAdd(currentNode)">
            <el-icon><component :is="icons.Plus" /></el-icon>
            新增部门
          </el-button>
        </div>
      </div>
    </template>

    <div class="tree-container">
      <el-input
        v-model="searchKeyword"
        class="filter-input"
        clearable
        placeholder="输入关键字进行过滤"
        :prefix-icon="icons.Search"
        size="small"
      />

      <el-tree
        ref="treeRef"
        :data="departmentList"
        :filter-node-method="filterNode"
        highlight-current
        lazy
        :load="loadNode"
        node-key="id"
        :props="treeProps"
        @node-click="handleNodeClick"
      >
        <template #default="{ node, data }">
          <div class="custom-tree-node">
            <div class="label-wrapper">
              <el-icon v-if="data.isExternal" class="tree-icon"><component :is="icons.User" /></el-icon>
              <el-icon v-else-if="node.expanded" class="tree-icon"><component :is="icons.FolderOpened" /></el-icon>
              <el-icon v-else class="tree-icon"><component :is="icons.Folder" /></el-icon>
              <el-tooltip :content="node.label" :disabled="node.label.length <= 8" placement="top" :show-after="500">
                <span class="node-label">{{ node.label }}</span>
              </el-tooltip>
            </div>
            <span v-if="data.isExternal && data.id !== 0 && data.id !== 'external'" class="operation-group">
              <el-tooltip content="新增子部门" placement="top">
                <el-button link type="primary" @click.stop="handleAdd(data)">
                  <el-icon><component :is="icons.Plus" /></el-icon>
                </el-button>
              </el-tooltip>
              <el-tooltip content="编辑部门" placement="top">
                <el-button link type="primary" @click.stop="handleEdit(data)">
                  <el-icon><component :is="icons.Edit" /></el-icon>
                </el-button>
              </el-tooltip>
              <el-tooltip content="删除部门" placement="top">
                <el-button link type="danger" @click.stop="handleDelete(node, data)">
                  <el-icon><component :is="icons.Delete" /></el-icon>
                </el-button>
              </el-tooltip>
            </span>
          </div>
        </template>
      </el-tree>
    </div>

    <!-- 部门表单弹窗 -->
    <el-dialog v-model="dialogVisible" destroy-on-close :title="isEdit ? '编辑部门' : '新增部门'" width="500px">
      <el-form ref="formRef" label-width="80px" :model="form" :rules="rules">
        <el-form-item label="部门名称" prop="name">
          <el-input v-model="form.name" placeholder="请输入部门名称" />
        </el-form-item>
        <el-form-item label="上级部门">
          <div class="parent-dept">{{ currentNode?.name || '-' }}</div>
        </el-form-item>
        <el-form-item label="状态" prop="status">
          <el-switch v-model="form.status" active-text="启用" :active-value="1" inactive-text="禁用" :inactive-value="0" />
        </el-form-item>
        <el-form-item label="备注" prop="remark">
          <el-input v-model="form.remark" placeholder="请输入备注信息" type="textarea" />
        </el-form-item>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="dialogVisible = false">取消</el-button>
          <el-button type="primary" @click="handleSubmit">确定</el-button>
        </span>
      </template>
    </el-dialog>
  </el-card>
</template>

<script lang="ts" setup>
import { Delete, Edit, Folder, FolderOpened, Plus, Search, User } from '@element-plus/icons-vue'
import type { FormInstance, FormRules } from 'element-plus'
import { ElMessage, ElMessageBox, ElTree } from 'element-plus'
import { markRaw, onMounted, ref, watch } from 'vue'
import Public from '~/src/api/public'
import { getDictionaryByKey } from '/@/api/dictionary'

interface DepartmentForm {
  id?: number
  name: string
  parentId: number
  status: number
  remark?: string
  isExternal?: boolean
}

interface Department {
  id: number | string
  name: string
  parentId?: number | string
  children?: Department[]
  isExternal?: boolean
  status?: number
  remark?: string
  hasChildren?: boolean
  isLeaf?: boolean
}

interface Emits {
  (e: 'update:modelValue', value: number): void
  (e: 'select', data: any, node: any): void
}

const emit = defineEmits<Emits>()

const treeRef = ref<InstanceType<typeof ElTree>>()
const formRef = ref<FormInstance>()
const searchKeyword = ref('')
const departmentList = ref<Department[]>([])
const dialogVisible = ref(false)
const isEdit = ref(false)
const currentNode = ref<Department | null>(null)

const form = ref<DepartmentForm>({
  name: '',
  parentId: 0,
  status: 1,
  remark: '',
})

const treeProps = markRaw({
  children: 'children',
  label: 'name',
  isLeaf: 'isLeaf',
})

const rules: FormRules = {
  name: [{ required: true, message: '请输入部门名称', trigger: 'blur' }],
}

// 使用 markRaw 标记图标组件
const icons = {
  Delete: markRaw(Delete),
  Edit: markRaw(Edit),
  Plus: markRaw(Plus),
  Search: markRaw(Search),
  Folder: markRaw(Folder),
  FolderOpened: markRaw(FolderOpened),
  User: markRaw(User),
}

// 过滤节点方法
const filterNode = markRaw((value: string, data: any) => {
  if (!value) return true
  return data.name.includes(value)
})

// 监听搜索关键词变化
watch(searchKeyword, (val) => {
  treeRef.value?.filter(val)
})

// 加载子节点
const loadNode = async (node: any, resolve: (data: Department[]) => void) => {
  // 如果是根节点，加载顶级部门
  if (node.level === 0) {
    try {
      const [internalDepts, externalDepts] = await Promise.all([fetchInternalTopDepartments(), fetchExternalDepartments()])

      // 获取排序规则
      const sort = await getDictionaryByKey('deptsort')
      const sortArray = (sort.result?.dataJson || '').split('、').filter(Boolean)

      // 对内部部门进行排序
      const sortedInternalDepts = internalDepts.sort((a, b) => {
        const aIndex = sortArray.indexOf(a.name)
        const bIndex = sortArray.indexOf(b.name)
        if (aIndex !== -1 && bIndex !== -1) {
          return aIndex - bIndex
        }
        if (aIndex !== -1) return -1
        if (bIndex !== -1) return 1
        return 0
      })

      // 创建外部人员根节点
      const externalRoot = {
        id: 'external',
        name: '外部人员',
        isExternal: true,
        children: externalDepts,
        isLeaf: externalDepts.length === 0,
      }

      resolve([...sortedInternalDepts, externalRoot])
    } catch (error) {
      console.error('加载顶级部门失败', error)
      resolve([])
    }
    return
  }

  // 如果是外部人员根节点
  if (node.data.id === 'external') {
    resolve(node.data.children || [])
    return
  }

  // 如果是外部部门节点，不需要加载子节点
  if (node.data.isExternal && node.data.id !== 'external') {
    if (node.data.children && node.data.children.length > 0) {
      resolve(node.data.children)
    } else {
      resolve([])
    }
    return
  }

  // 如果是内部部门节点，加载子部门
  try {
    const childDepts = await fetchInternalChildDepartments(node.data.id)
    resolve(childDepts)
  } catch (error) {
    console.error('加载子部门失败', error)
    resolve([])
  }
}

// 获取内部顶级部门
const fetchInternalTopDepartments = async () => {
  try {
    const response = await Public.getDetailApi({
      url: '/api/employees/departments/list',
      params: {
        page: 1,
        limit: 100,
        parentId: null,
      },
    })
    const { code, result } = response as unknown as { code: number; result: { rows: any[] } }
    if (code === 0 && result.rows) {
      return result.rows.map((dept) => ({
        ...dept,
        hasChildren: true,
        isLeaf: false,
      }))
    }
    return []
  } catch (error) {
    console.error('获取内部顶级部门失败:', error)
    return []
  }
}

// 获取内部子部门
const fetchInternalChildDepartments = async (parentId: number | string) => {
  try {
    const response = await Public.getDetailApi({
      url: '/api/employees/departments/list',
      params: {
        page: 1,
        limit: 100,
        parentId,
      },
    })
    const { code, result } = response as unknown as { code: number; result: { rows: any[] } }
    if (code === 0 && result.rows) {
      return result.rows.map((dept) => ({
        ...dept,
        hasChildren: true,
        isLeaf: false,
      }))
    }
    return []
  } catch (error) {
    console.error('获取内部子部门失败:', error)
    return []
  }
}

// 获取外部部门树数据
const fetchExternalDepartments = async () => {
  try {
    const response = await Public.getDetailApi({ url: '/api/department' })
    const { code, result } = response as unknown as { code: number; result: any[] }
    if (code === 0) {
      // 转换为带有isExternal标记的部门数据
      const externalDepts = result.map((dept) => ({
        ...dept,
        isExternal: true,
        id: `ext-${dept.id}`, // 为避免ID冲突添加前缀
        isLeaf: !dept.children || dept.children.length === 0,
        children: dept.children
          ? dept.children.map((child: any) => ({
              ...child,
              isExternal: true,
              id: `ext-${child.id}`,
              isLeaf: !child.children || child.children.length === 0,
            }))
          : [],
      }))
      return externalDepts
    }
    return []
  } catch (error) {
    console.error('获取外部部门树失败:', error)
    return []
  }
}

// 初始化部门树
const initDepartmentTree = async () => {
  // 使用懒加载，初始化时不需要加载数据
  departmentList.value = []
}

// 处理节点点击
const handleNodeClick = (data: any, node: any) => {
  currentNode.value = data
  emit('update:modelValue', data.id)
  emit('select', data, node)
}

// 处理新增
const handleAdd = (data: any) => {
  isEdit.value = false
  // 如果是外部人员根节点，parentId 设置为 -1
  // 如果是外部部门，需要去掉前缀获取真实 ID
  const parentId =
    data.id === 'external' ? 0 : typeof data.id === 'string' && data.id.startsWith('ext-') ? parseInt(data.id.replace('ext-', '')) : data.id

  form.value = {
    name: '',
    parentId,
    status: 1,
    remark: '',
    isExternal: true,
  }
  dialogVisible.value = true
}

// 处理编辑
const handleEdit = (data: any) => {
  isEdit.value = true

  // 如果是外部部门，需要去掉前缀
  const id = typeof data.id === 'string' && data.id.startsWith('ext-') ? parseInt(data.id.replace('ext-', '')) : data.id

  form.value = {
    ...data,
    id,
    parentId: data.parentId || 0,
    isExternal: data.isExternal || false,
  }
  dialogVisible.value = true
}

// 处理删除
const handleDelete = (node: any, data: any) => {
  ElMessageBox.confirm('此操作将永久删除该部门及其子部门, 是否继续?', '提示', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning',
  })
    .then(async () => {
      try {
        // 根据是否为外部部门决定删除API
        const url = data.isExternal ? '/api/department' : '/api/employees/departments'

        // 如果是外部部门ID，需要去除前缀
        const id = typeof data.id === 'string' && data.id.startsWith('ext-') ? data.id.replace('ext-', '') : data.id

        await Public.delApi({ url, id })
        ElMessage.success('删除成功')

        // 重新加载整个树
        await loadNode({ level: 0 }, (data) => {
          departmentList.value = data
        })

        // 清除当前选中状态
        currentNode.value = null
        emit('update:modelValue')
        emit('select', null, null)
      } catch (error) {
        console.error('删除失败:', error)
        ElMessage.error('删除失败')
      }
    })
    .catch(() => {
      ElMessage.info('已取消删除')
    })
}

// 处理表单提交
const handleSubmit = async () => {
  if (!formRef.value) return

  await formRef.value.validate(async (valid) => {
    if (valid) {
      try {
        // 根据是否为外部部门选择不同的API
        const url = form.value.isExternal ? '/api/department' : '/api/employees/departments'

        if (isEdit.value) {
          await Public.editApi({ url, data: form.value })
          ElMessage.success('更新成功')
        } else {
          await Public.addApi({ url, data: form.value })
          ElMessage.success('添加成功')
        }
        dialogVisible.value = false

        // 重新加载整个树
        await loadNode({ level: 0 }, (data) => {
          departmentList.value = data
        })
      } catch (error) {
        console.error('提交失败:', error)
        ElMessage.error('操作失败')
      }
    }
  })
}

onMounted(() => {
  initDepartmentTree()
})
</script>

<style scoped>
.department-tree-card {
  height: 100%;
}

.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
}

.title {
  font-weight: bold;
  font-size: 16px;
}

.tree-container {
  padding: 10px;
}

.filter-input {
  margin-bottom: 15px;
}

.custom-tree-node {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-right: 8px;
}

.label-wrapper {
  display: flex;
  align-items: center;
}

.tree-icon {
  margin-right: 6px;
}

.node-label {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 150px;
  display: inline-block;
}

.operation-group {
  display: none;
}

.custom-tree-node:hover .operation-group {
  display: inline-flex;
}

.parent-dept {
  line-height: 32px;
  color: #606266;
}
</style>
